home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Just Call Me Internet
/
Just Call Me Internet.iso
/
prog
/
atari
/
c
/
pgpsrc23
/
config.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-06-13
|
14KB
|
560 lines
/* config.c - config file parser by Peter Gutmann
Parses config file for PGP
Modified 24 Jun 92 - HAJK
Misc fixes for VAX C restrictions.
*/
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "usuals.h"
#include "fileio.h"
#include "pgp.h"
#include "config.h"
#include "charset.h"
static int lookup( char *key, int keyLength, char *keyWords[], int range );
static int extractToken( char *buffer, int *endIndex, int *length );
static int getaString( char *buffer, int *endIndex );
static int getAssignment( char *buffer, int *endIndex, INPUT_TYPE settingType );
static void processAssignment( int intrinsicIndex );
/* The external config variables we can set here are referenced in pgp.h */
/* Return values */
#define ERROR -1
#define OK 0
/* The types of error we check for */
enum { NO_ERROR, ILLEGAL_CHAR_ERROR, LINELENGTH_ERROR };
#define CPM_EOF 0x1A /* ^Z = CPM EOF char */
#define MAX_ERRORS 3 /* Max.no.errors before we give up */
#define LINEBUF_SIZE 100 /* Size of input buffer */
static int line; /* The line on which an error occurred */
static int errCount; /* Total error count */
static boolean hasError; /* Whether this line has an error in it */
/* The settings parsed out by getAssignment() */
static char str[ LINEBUF_SIZE ];
static int value;
static boolean flag;
static char *errtag; /* prefix for printing error messages */
static char optstr[100]; /* option being processed */
/* A .CFG file roughly follows the format used in the world-famous HPACK
archiver and is as follows:
- Leading spaces/tabs (whitespace) are ignored.
- Lines with a '#' as the first non-whitespace character are treated as
comment lines.
- All other lines are treated as config options for the program.
- Lines may be terminated by either linefeeds, carriage returns, or
carriage return/linefeed pairs (the latter being the DOS default
method of storing text files).
- Config options have the form:
<option> '=' <setting>
where <setting> may be 'on', 'off', a numeric value, or a string
value.
- If strings have spaces or the '#' character inside them they must be
surrounded by quote marks '"' */
/* Intrinsic variables */
#define NO_INTRINSICS (sizeof(intrinsics) / sizeof(intrinsics[0]))
enum
{ ARMOR, COMPRESS, SHOWPASS, KEEPBINARY, LANGUAGE,
MYNAME, TEXTMODE, TMP, TZFIX, VERBOSE, BAKRING,
ARMORLINES, COMPLETES_NEEDED, MARGINALS_NEEDED, PAGER,
CERT_DEPTH, CHARSET, CLEAR, SELF_ENCRYPT,
INTERACTIVE, PKCS_COMPAT,
/* options below this line can only be used as command line
* "long" options */
#define CONFIG_INTRINSICS BATCHMODE
BATCHMODE, FORCE
};
static char *intrinsics[] =
{ "ARMOR", "COMPRESS", "SHOWPASS", "KEEPBINARY", "LANGUAGE",
"MYNAME", "TEXTMODE", "TMP", "TZFIX", "VERBOSE", "BAKRING",
"ARMORLINES", "COMPLETES_NEEDED", "MARGINALS_NEEDED", "PAGER",
"CERT_DEPTH", "CHARSET", "CLEARSIG", "ENCRYPTTOSELF",
"INTERACTIVE", "PKCS_COMPAT",
/* command line only */
"BATCHMODE", "FORCE",
};
static INPUT_TYPE intrinsicType[] =
{ BOOL, BOOL, BOOL, BOOL, STRING,
STRING, BOOL, STRING, NUMERIC, NUMERIC, STRING,
NUMERIC, NUMERIC, NUMERIC, STRING,
NUMERIC, STRING, BOOL, BOOL,
BOOL, NUMERIC,
/* command line only */
BOOL, BOOL,
};
/* Possible settings for variables */
#define NO_SETTINGS 2
static char *settings[] = { "OFF", "ON" };
/* Search a list of keywords for a match */
static int lookup( char *key, int keyLength, char *keyWords[], int range )
{
int indx, pos = 0, matches = 0;
strncpy(optstr, key, keyLength);
optstr[keyLength] = '\0';
/* Make the search case insensitive */
for( indx = 0; indx < keyLength; indx++ )
key[ indx ] = to_upper( key[ indx ] );
for( indx = 0; indx < range; indx++ )
if( !strncmp( key, keyWords[ indx ], keyLength ) )
{ if (strlen(keyWords[indx]) == keyLength)
return indx; /* exact match */
pos = indx;
++matches;
}
switch (matches)
{ case 0: fprintf(stderr, "%s: unknown keyword: \"%s\"\n", errtag, optstr); break;
case 1: return pos;
default: fprintf(stderr, "%s: \"%s\" is ambiguous\n", errtag, optstr);
}
return ERROR;
}
/* Extract a token from a buffer */
static int extractToken( char *buffer, int *endIndex, int *length )
{
int indx = 0, tokenStart;
char ch;
/* Skip whitespace */
for( ch = buffer[ indx ]; ch && ( ch == ' ' || ch == '\t' ); ch = buffer[ indx ] )
indx++;
tokenStart = indx;
/* Find end of setting */
while( indx < LINEBUF_SIZE && ( ch = buffer[ indx ] ) != '\0' && ch != ' ' && ch != '\t' )
indx++;
*endIndex += indx;
*length = indx - tokenStart;
/* Return start position of token in buffer */
return( tokenStart );
}
/* Get a string constant */
static int getaString( char *buffer, int *endIndex )
{
boolean noQuote = FALSE;
int stringIndex = 0, bufIndex = 1;
char ch = *buffer;
/* Skip whitespace */
while( ch && ( ch == ' ' || ch == '\t' ) )
ch = buffer[ bufIndex++ ];
/* Check for non-string */
if( ch != '\"' )
{
*endIndex += bufIndex;
/* Check for special case of null string */
if( !ch )
{
*str = '\0';
return( OK );
}
/* Use nasty non-rigorous string format */
noQuote = TRUE;
}
/* Get first char of string */
if( !noQuote )
ch = buffer[ bufIndex++ ];
/* Get string into string */
while( ch && ch != '\"' )
{
/* Exit on '#' if using non-rigorous format */
if( noQuote && ch == '#' )
break;
str[ stringIndex++ ] = ch;
ch = buffer[ bufIndex++ ];
}
/* If using the non-rigorous format, stomp trailing spaces */
if( noQuote )
while( stringIndex > 0 && str[ stringIndex - 1 ] == ' ' )
stringIndex--;
str[ stringIndex++ ] = '\0';
*endIndex += bufIndex;
/* Check for missing string terminator */
if( ch != '\"' && !noQuote )
{
if (line)
fprintf(stderr, "%s: unterminated string in line %d\n", errtag, line );
else
fprintf(stderr, "unterminated string: '\"%s'\n", str );
hasError = TRUE;
errCount++;
return( ERROR );
}
return( OK );
}
/* Get an assignment to an intrinsic */
static int getAssignment( char *buffer, int *endIndex, INPUT_TYPE settingType )
{
int settingIndex = 0, length;
buffer += extractToken( buffer, endIndex, &length );
/* Check for an assignment operator */
if ( *buffer != '=' )
{
if (line)
fprintf(stderr, "%s: expected '=' in line %d\n", errtag, line );
else
fprintf(stderr, "%s: expected '=' after \"%s\"\n", errtag, optstr);
hasError = TRUE;
errCount++;
return( ERROR );
}
buffer++; /* Skip '=' */
buffer += extractToken( buffer, endIndex, &length );
switch( settingType )
{
case BOOL:
/* Check for known intrinsic - really more general than just
checking for TRUE or FALSE */
if( ( settingIndex = lookup( buffer, length, settings, NO_SETTINGS ) ) == ERROR )
{
hasError = TRUE;
errCount++;
return( ERROR );
}
flag = ( settingIndex == 0 ) ? FALSE : TRUE;
break;
case STRING:
/* Get a string */
getaString( buffer, &length );
break;
case NUMERIC:
/* Get numeric input. Error checking is a pain since atoi()
has no real equivalent of NAN */
value = atoi( buffer );
break;
}
return( settingIndex );
}
/* Process an assignment */
static void processAssignment( int intrinsicIndex )
{
if( !hasError )
switch( intrinsicIndex )
{
case ARMOR:
emit_radix_64 = flag;
break;
case COMPRESS:
compress_enabled = flag;
break;
case SHOWPASS:
showpass = flag;
break;
case KEEPBINARY:
keepctx = flag;
break;
case LANGUAGE:
strncpy(language, str, 15);
break;
case BAKRING:
strcpy(floppyring, str);
break;
case MYNAME:
strcpy(my_name, str);
break;
case TEXTMODE:
if( flag )
literal_mode = MODE_TEXT;
else
literal_mode = MODE_BINARY;
break;
case TMP:
/* directory pathname to store temp files */
settmpdir(str);
break;
case TZFIX:
/* How many hours to add to time() to get GMT. */
/* Compute seconds from hours to shift to GMT: */
timeshift = 3600L * (long) value;
break;
case VERBOSE:
switch (value)
{
case 0: quietmode = TRUE; verbose = FALSE; break;
case 1: quietmode = FALSE; verbose = FALSE; break;
case 2: quietmode = FALSE; verbose = TRUE; break;
default: quietmode = FALSE; verbose = FALSE;
}
break;
case ARMORLINES:
pem_lines = value;
break;
case MARGINALS_NEEDED:
marg_min = value;
if (marg_min < 1)
marg_min = 1;
break;
case COMPLETES_NEEDED:
compl_min = value;
if (compl_min < 1)
compl_min = 1;
if (compl_min > 4)
compl_min = 4;
break;
case CERT_DEPTH:
max_cert_depth = value;
if (max_cert_depth < 0)
max_cert_depth = 0;
if (max_cert_depth > 8)
max_cert_depth = 8;
break;
case PAGER:
strcpy(pager, str);
break;
case CHARSET:
strcpy(charset, str);
break;
case CLEAR:
clear_signatures = flag;
break;
case SELF_ENCRYPT:
encrypt_to_self = flag;
break;
case INTERACTIVE:
interactive_add = flag;
break;
case BATCHMODE: batchmode = flag; break;
case FORCE: force_flag = flag; break;
case PKCS_COMPAT: pkcs_compat = value; break;
}
}
/* Process an option on a line by itself. This expects options which are
taken from the command-line, and is less finicky about errors than the
config-file version */
int processConfigLine( char *option )
{
int indx, intrinsicIndex;
char ch;
/* Give it a pseudo-linenumber of 0 */
line = 0;
errtag = "pgp";
errCount = 0;
for( indx = 0;
indx < LINEBUF_SIZE && ( ch = option[ indx ] ) != '\0' &&
ch != ' ' && ch != '\t' && ch != '=';
indx++ );
if( ( intrinsicIndex = lookup( ( char * ) option, indx, intrinsics, NO_INTRINSICS ) ) == ERROR )
return -1;
if (option[indx] == '\0' && intrinsicType[intrinsicIndex] == BOOL)
{ /* boolean option, no '=' means TRUE */
flag = TRUE;
processAssignment(intrinsicIndex);
}
else /* Get the value to set to, either as a string, a
numeric value, or a boolean flag */
if (getAssignment( ( char * ) option + indx, &indx, intrinsicType[ intrinsicIndex ] ) != ERROR)
processAssignment( intrinsicIndex );
return(errCount ? -1 : 0);
}
/* Process a config file */
int processConfigFile( char *configFileName )
{
FILE *configFilePtr;
int ch = 0, theCh;
int errType, errPos = 0, lineBufCount, intrinsicIndex;
int indx;
char inBuffer[ LINEBUF_SIZE ];
line = 1;
errCount = 0;
errtag = "config.txt";
if( ( configFilePtr = fopen( configFileName, FOPRTXT ) ) == NULL )
{
fprintf(stderr, "Cannot open configuration file %s\n", configFileName );
return( OK ); /* treat like empty config file */
}
/* Process each line in the configFile */
while( ch != EOF )
{
/* Skip whitespace */
while( ( ( ch = getc( configFilePtr ) ) == ' ' || ch == '\t' ) && ch != EOF )
;
/* Get a line into the inBuffer */
hasError = FALSE;
lineBufCount = 0;
errType = NO_ERROR;
while( ch != '\r' && ch != '\n' && ch != CPM_EOF && ch != EOF )
{
/* Check for an illegal char in the data */
if( ( ch < ' ' || ch > '~' ) && ch != '\r' && ch != '\n' &&
ch != ' ' && ch != '\t' && ch != CPM_EOF && ch != EOF )
{
if( errType == NO_ERROR )
/* Save position of first illegal char */
errPos = lineBufCount;
errType = ILLEGAL_CHAR_ERROR;
}
/* Make sure the path is of the correct length. Note that the
code is ordered so that a LINELENGTH_ERROR takes precedence over
an ILLEGAL_CHAR_ERROR */
if( lineBufCount > LINEBUF_SIZE )
errType = LINELENGTH_ERROR;
else
inBuffer[ lineBufCount++ ] = ch;
if( ( ch = getc( configFilePtr ) ) == '#' )
{
/* Skip comment section and trailing whitespace */
while( ch != '\r' && ch != '\n' && ch != CPM_EOF && ch != EOF )
ch = getc( configFilePtr );
break;
}
}
/* Skip trailing whitespace and add der terminador */
while(lineBufCount && (( theCh = inBuffer[ lineBufCount - 1 ] ) == ' ' || theCh == '\t' ))
lineBufCount--;
inBuffer[ lineBufCount ] = '\0';
/* Process the line unless its a blank or comment line */
if( lineBufCount && *inBuffer != '#' )
{
switch( errType )
{
case LINELENGTH_ERROR:
fprintf(stderr, "%s: line '%.30s...' too long\n", errtag, inBuffer );
errCount++;
break;
case ILLEGAL_CHAR_ERROR:
fprintf(stderr, "> %s\n ", inBuffer );
fprintf(stderr, "%*s^\n", errPos, "");
fprintf(stderr, "%s: bad character in command on line %d\n", errtag, line );
errCount++;
break;
default:
for( indx = 0;
indx < LINEBUF_SIZE && ( ch = inBuffer[ indx ] ) != '\0'
&& ch != ' ' && ch != '\t' && ch != '=';
indx++ )
;
if( ( intrinsicIndex = lookup( inBuffer, indx, intrinsics, CONFIG_INTRINSICS ) ) == ERROR )
{
errCount++;
}
else
{
/* Get the value to set to, either as a string, a
numeric value, or a boolean flag */
getAssignment( inBuffer + indx, &indx, intrinsicType[ intrinsicIndex ] );
processAssignment( intrinsicIndex );
}
}
}
/* Handle special-case of ^Z if configFile came off an MSDOS system */
if( ch == CPM_EOF )
ch = EOF;
/* Exit if there are too many errors */
if( errCount >= MAX_ERRORS )
break;
line++;
}
fclose( configFilePtr );
/* Exit if there were errors */
if( errCount )
{
fprintf(stderr, "%s: %s%d error(s) detected\n\n", configFileName, ( errCount >= MAX_ERRORS ) ?
"Maximum level of " : "", errCount );
return( ERROR );
}
return( OK );
}